package com.zhoyq.tools;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 仅支持windows
 * 增加linux支持
 * lsof -i:8080 | awk '{if(NR>1){print $2}}' | xargs -r kill -9
 *
 * @author zhoyq
 */
public class App {

    private Set<Integer> ports;

    public static void main(String[] args) throws InterruptedException {
        System.out.println(args[0]);
        Set<Integer> ports = new HashSet<>();
        for (String p : args) {
            ports.add(Integer.valueOf(p));
        }
        App kill = new App();
        kill.ports = ports;
        System.out.println("need kill " + ports.size() + " num");
        if(kill.checkLinux()){
            for (Integer pid : ports) {
                kill.startLinux(pid);
            }
        }else{
            for (Integer pid : ports) {
                kill.startWindows(pid);
            }
        }
        System.out.println("SUCCESS");
        Thread.sleep(5000);
        System.exit(0);
    }

    private boolean checkLinux(){
        String pathSep = System.getProperty("path.separator");
        return ":".equals(pathSep);
    }

    private void startWindows(int port){
        Runtime runtime = Runtime.getRuntime();
        try {
            //查找进程号
            Process p = runtime.exec("cmd /c netstat -ano | findstr \"" + port + "\"");
            InputStream inputStream = p.getInputStream();
            List<String> read = read(inputStream);
            if (read.size() == 0) {
                System.out.println("找不到该端口的进程");
                try {
                    Thread.sleep(6000);
                    System.exit(0);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                for (String string : read) {
                    System.out.println(string);
                }
                System.out.println("找到" + read.size() + "个进程，正在准备清理");
                kill(read);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 开始杀死端口号
     *
     * @param port 端口号
     */
    private void startLinux(int port) {
        Runtime runtime = Runtime.getRuntime();
        try {
            runtime.exec("lsof -i:"+ port +" | awk '{if(NR>1){print $2}}' | xargs -r kill -9");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private Pattern pattern = Pattern.compile("^ *[a-zA-Z]+ +\\S+");

    /**
     * 验证此行是否为指定的端口，因为 findstr 命令会是把包含的找出来，例如查找80端口，但是会把8099查找出来
     *
     * @param str 要查找的字符串
     * @return 是否含有
     */
    private boolean validPort(String str) {
        Matcher matcher = pattern.matcher(str);
        String find = matcher.group();
        int spStart = find.lastIndexOf(":");
        find = find.substring(spStart + 1);

        int port;
        try {
            port = Integer.parseInt(find);
        } catch (NumberFormatException e) {
            System.out.println("查找到错误的端口:" + find);
            return false;
        }
        return this.ports.contains(port);
    }

    /**
     * 更换为一个Set，去掉重复的pid值
     *
     * @param data pid列表
     */
    private void kill(List<String> data) {
        Set<Integer> pIds = new HashSet<>();
        for (String line : data) {
            int offset = line.lastIndexOf(" ");
            String spId = line.substring(offset);
            spId = spId.replaceAll(" ", "");
            int pid = 0;
            try {
                pid = Integer.parseInt(spId);
            } catch (NumberFormatException e) {
                System.out.println("获取的进程号错误:" + spId);
            }
            pIds.add(pid);
        }
        killWithPid(pIds);
    }

    /**
     * 一次性杀除所有的端口
     *
     * @param pIds 去重后的PID
     */
    private void killWithPid(Set<Integer> pIds) {
        for (Integer pid : pIds) {
            try {
                Process process = Runtime.getRuntime().exec("taskkill /F /pid " + pid + "");
                InputStream inputStream = process.getInputStream();
                String txt = readTxt(inputStream);
                System.out.println(txt);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    private List<String> read(InputStream in ) throws IOException {
        List<String> data = new ArrayList<>();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
        String line;
        while ((line = reader.readLine()) != null) {
            boolean validPort = validPort(line);
            if (validPort) {
                data.add(line);
            }
        }
        reader.close();
        return data;
    }

    private String readTxt(InputStream in ) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(in, "GBK"));
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
        reader.close();
        return sb.toString();
    }
}
